//
// Copyright 2018 Google Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// stylelint-disable selector-class-pattern --
// Selector '.mdc-*' should only be used in this project.

@use 'sass:math';
@use '@material/density/functions' as density-functions;
@use '@material/elevation/mixins' as elevation-mixins;
@use '@material/feature-targeting/feature-targeting';
@use '@material/ripple/ripple';
@use '@material/ripple/ripple-theme';
@use '@material/rtl/rtl';
@use '@material/theme/theme';
@use './functions';
@use './variables';
@use '@material/dom/mixins' as dom-mixins;

// Temporary suffix to add to shared selectors between versions for migration
$deprecated-suffix: '-deprecated' !default;

//
// Public
//

@mixin core-styles($query: feature-targeting.all()) {
  @include without-ripple($query);
  @include ripple($query);
}

// This API is intended for use by frameworks that may want to separate the ripple-related styles from the other
// switch styles. It is recommended that most users use `mdc-switch-core-styles` instead.
@mixin without-ripple($query: feature-targeting.all()) {
  // postcss-bem-linter: define switch

  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include density(variables.$density-scale, $query: $query);

  .mdc-switch#{$deprecated-suffix} {
    @include feature-targeting.targets($feat-structure) {
      @include base_;
    }

    @include toggled-on-track-color(variables.$baseline-theme-color, $query);
    @include toggled-on-thumb-color(variables.$baseline-theme-color, $query);
    @include toggled-off-track-color(
      variables.$toggled-off-track-color,
      $query
    );
    @include toggled-off-thumb-color(
      variables.$toggled-off-thumb-color,
      $query
    );
  }

  .mdc-switch__native-control {
    @include feature-targeting.targets($feat-structure) {
      @include native-control_;
    }
    @include feature-targeting.targets($feat-animation) {
      transition: functions.transition(transform);
    }
  }

  .mdc-switch__track#{$deprecated-suffix} {
    @include track_($query);
  }

  .mdc-switch__thumb-underlay {
    @include thumb-underlay_($query);
  }

  .mdc-switch__thumb {
    @include thumb_($query);
  }

  .mdc-switch--checked {
    @include feature-targeting.targets($feat-structure) {
      .mdc-switch__track#{$deprecated-suffix} {
        @include track-checked_;
      }

      .mdc-switch__thumb-underlay {
        @include thumb-underlay-checked_;
      }

      .mdc-switch__native-control {
        @include native-control-checked_;
      }
    }
  }

  .mdc-switch--disabled {
    @include feature-targeting.targets($feat-structure) {
      @include disabled-base_;

      .mdc-switch__thumb {
        @include thumb-disabled_;
      }

      .mdc-switch__native-control {
        @include native-control-disabled_;
      }
    }
  }

  // postcss-bem-linter: end
}

// This API is intended for use by frameworks that may want to separate the ripple-related styles from the other
// switch styles. It is recommended that most users use `mdc-switch-core-styles` instead.
@mixin ripple($query: feature-targeting.all()) {
  @include ripple.common($query); // COPYBARA_COMMENT_THIS_LINE

  .mdc-switch#{$deprecated-suffix} {
    @include toggled-off-ripple-color(
      variables.$toggled-off-ripple-color,
      $query
    );
  }

  .mdc-switch__thumb-underlay {
    @include ripple.surface($query);
    @include ripple.radius-unbounded(100%, $query);
    @include ripple-theme.states(
      variables.$baseline-theme-color,
      false,
      $query
    );
  }
}

@mixin toggled-on-color($color, $query: feature-targeting.all()) {
  @include toggled-on-track-color($color, $query);
  @include toggled-on-thumb-color($color, $query);
  @include toggled-on-ripple-color($color, $query);
}

@mixin toggled-off-color($color, $query: feature-targeting.all()) {
  @include toggled-off-track-color($color, $query);
  @include toggled-off-thumb-color($color, $query);
  @include toggled-off-ripple-color($color, $query);
}

@mixin toggled-on-track-color($color, $query: feature-targeting.all()) {
  $feat-color: feature-targeting.create-target($query, color);

  &.mdc-switch--checked .mdc-switch__track#{$deprecated-suffix} {
    @include feature-targeting.targets($feat-color) {
      @include theme.property(background-color, $color);
    }
  }
}

@mixin toggled-on-thumb-color($color, $query: feature-targeting.all()) {
  $feat-color: feature-targeting.create-target($query, color);

  &.mdc-switch--checked .mdc-switch__thumb {
    @include feature-targeting.targets($feat-color) {
      @include theme.property(background-color, $color);
      @include theme.property(border-color, $color);
    }
  }
}

@mixin toggled-on-ripple-color($color, $query: feature-targeting.all()) {
  &.mdc-switch--checked .mdc-switch__thumb-underlay {
    @include ripple-theme.states($color, false, $query);
  }
}

@mixin toggled-off-track-color($color, $query: feature-targeting.all()) {
  $feat-color: feature-targeting.create-target($query, color);

  &:not(.mdc-switch--checked) .mdc-switch__track#{$deprecated-suffix} {
    @include feature-targeting.targets($feat-color) {
      @include theme.property(background-color, $color);
    }
  }
}

@mixin toggled-off-thumb-color($color, $query: feature-targeting.all()) {
  $feat-color: feature-targeting.create-target($query, color);

  &:not(.mdc-switch--checked) .mdc-switch__thumb {
    @include feature-targeting.targets($feat-color) {
      @include theme.property(background-color, $color);
      @include theme.property(border-color, $color);
    }
  }
}

@mixin toggled-off-ripple-color($color, $query: feature-targeting.all()) {
  &:not(.mdc-switch--checked) .mdc-switch__thumb-underlay {
    @include ripple-theme.states($color, false, $query);
  }
}

///
/// Sets density scale for switch.
///
/// @param {Number | String} $density-scale - Density scale value for component.
///     Supported density scale values are `-5`, `-4`, `-3`, `-2`, `-1`,
///     `0` (default).
///
@mixin density($density-scale, $query: feature-targeting.all()) {
  $size: density-functions.prop-value(
    $density-config: variables.$density-config,
    $density-scale: $density-scale,
    $property-name: size,
  );

  @include ripple-size($size, $query: $query);
}

@mixin ripple-size($ripple-size, $query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  // Position for the tap target that contains the thumb to align the thumb
  // correctly offset from the track.
  $tap-target-initial-position: math.div(-$ripple-size, 2) +
    math.div(variables.$thumb-diameter, 2);
  // Value to cover the whole switch area (including the ripple) with the
  // native control.
  $native-control-width: variables.$track-width +
    ($ripple-size - variables.$thumb-diameter);

  .mdc-switch__thumb-underlay {
    @include feature-targeting.targets($feat-structure) {
      @include rtl.reflexive-position(left, $tap-target-initial-position);

      // Ensures the knob is centered on the track.
      top: -(math.div($ripple-size - variables.$track-height, 2));
      width: $ripple-size;
      height: $ripple-size;
    }
  }

  .mdc-switch__native-control {
    @include feature-targeting.targets($feat-structure) {
      width: $native-control-width;
      height: $ripple-size;
    }
  }
}

///
/// Customizes ripple opacities surrounding the thumb in `hover`, `focus`, or `press` states
/// The customizations apply to both on and off switches to ensure symmetry
/// @param {map} $opacity-map - map specifying custom opacity of zero or more states
///
@mixin ripple-states-opacity(
  $opacity-map: (),
  $query: feature-targeting.all()
) {
  // Ensure sufficient specificity to override base state opacities
  &.mdc-switch#{$deprecated-suffix} .mdc-switch__thumb-underlay {
    @include ripple-theme.states-opacities($opacity-map, $query: $query);
  }
}

//
// Private
//

// Structure
@mixin base_ {
  display: inline-block;
  position: relative;
  outline: none;
  user-select: none;
}

@mixin track_($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    box-sizing: border-box;
    width: variables.$track-width;
    height: variables.$track-height;
    border: 1px solid transparent;
    border-radius: math.div(variables.$track-height, 2);
    opacity: 0.38;
  }

  @include feature-targeting.targets($feat-animation) {
    transition: functions.transition(opacity),
      functions.transition(background-color), functions.transition(border-color);
  }
}

@mixin thumb-underlay_($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-color: feature-targeting.create-target($query, color);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    display: flex;
    position: absolute;
    align-items: center;
    justify-content: center;
    transform: translateX(0);
  }

  @include feature-targeting.targets($feat-animation) {
    transition: functions.transition(transform),
      functions.transition(background-color), functions.transition(border-color);
  }
}

@mixin native-control_ {
  @include rtl.reflexive-position(left, 0);

  position: absolute;
  top: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
  pointer-events: auto;
}

@mixin thumb_($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);
  $feat-color: feature-targeting.create-target($query, color);

  @include elevation-mixins.elevation($z-value: 2, $query: $query);

  @include feature-targeting.targets($feat-structure) {
    box-sizing: border-box;
    width: variables.$thumb-diameter;
    height: variables.$thumb-diameter;
    border: math.div(variables.$thumb-diameter, 2) solid;
    border-radius: 50%;
    // Allow events to go through to the native control, necessary for IE and Edge.
    pointer-events: none;
    z-index: 1;
  }
}

// Checked state

@mixin track-checked_ {
  opacity: 0.54;
}

@mixin thumb-underlay-checked_ {
  transform: translateX(variables.$thumb-active-margin);

  @include rtl.rtl {
    transform: translateX(-(variables.$thumb-active-margin));
  }
}

@mixin native-control-checked_ {
  // Translate the native control the opposite direction so that the tap target stays the same.
  transform: translateX(-(variables.$thumb-active-margin));

  @include rtl.rtl {
    transform: translateX(variables.$thumb-active-margin);
  }
}

// Disabled state

@mixin disabled-base_ {
  opacity: 0.38;
  pointer-events: none;
}

@mixin thumb-disabled_ {
  border-width: 1px; // In high contrast mode, only show outline of knob.
}

@mixin native-control-disabled_ {
  cursor: default;
  pointer-events: none;
}

///
/// Includes ad-hoc high contrast mode support.
///
@mixin high-contrast-mode-shim($query: feature-targeting.all()) {
  & .mdc-ripple-upgraded--background-focused .mdc-switch__thumb::before {
    @include dom-mixins.transparent-border($border-width: 3px);
  }
}
